home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1993…ch: Other People's Memory / ADC Developer CD (1993-03) (''Other People's Memory'')_iso / Dev.CD Mar 93.iso / Development Platforms / LISP Related / LISP Goodies / defsys 5.0 / defsys.l < prev    next >
Encoding:
Text File  |  1992-09-02  |  48.3 KB  |  1,338 lines  |  [TEXT/CCL2]

  1. ; -*- mode:     CL -*- ----------------------------------------------------- ;
  2. ; File:         defsys.l
  3. ; Description:  A portable defsystem facility written in pure Common LISP.
  4. ;               This is a largely extended version of the original
  5. ;               defsystem written by Doug Rand
  6. ; Author:       dougr@eddie.mit.edu, Joachim H. Laubsch (laubsch@hplabs.hp.com)
  7. ; Created:      28-Jul-89
  8. ; Modified:     Tue Aug 11 12:04:54 1992 (Joachim H. Laubsch)
  9. ; Language:     CL
  10. ; Package:      DEFSYSTEM
  11. ;
  12. ;;; *************************************************************************
  13. ;;; Copyright (c) 1989, Hewlett-Packard Company
  14. ;;; All rights reserved.
  15. ;;;
  16. ;;; Use and copying of this software and preparation of derivative works
  17. ;;; based upon this software are permitted.  Any distribution of this
  18. ;;; software or derivative works must comply with all applicable United
  19. ;;; States export control laws.
  20. ;;; 
  21. ;;; This software is made available AS IS, and Hewlett-Packard Company
  22. ;;; makes no warranty about the software, its performance or its conformity
  23. ;;; to any specification.
  24. ;;; 
  25. ;;; Suggestions, comments and requests for improvements are welcome
  26. ;;; and should be mailed to laubsch@hplabs.com.
  27. ;;; *************************************************************************
  28. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  29.  
  30. (in-package "DEFSYSTEM")
  31. (require "P-defsys")
  32.  
  33. #+:KCL(proclaim '(optimize (speed 1)))
  34. (proclaim '(special *suffixes*))
  35. #-:LUCID
  36. (defvar *LOAD-IF-SOURCE-NEWER* :QUERY)
  37. #+(and :LUCID (not :LCL4.0))
  38. (import 'SYSTEM:*LOAD-IF-SOURCE-NEWER*)
  39. #+(and :LUCID  :LCL4.0)
  40. (import 'LCL:*LOAD-IF-SOURCE-NEWER*)
  41.  
  42. (defstruct (system (:print-function print-system))
  43.   (name "")
  44.   (default-pathname   (pathname "")   :type (or cons pathname))
  45.   (default-package    *package*)
  46.   (needed-systems      nil            :type list)
  47.   (load-before-compile nil            :type list)
  48.   (module-list         nil            :type list)
  49.   (needs-update        nil)
  50.   (modules             (make-hash-table :size 16 :rehash-size 8 :test #'equal))
  51.   (default-load-module t)        ; t means load all
  52.   (memo                nil            :type list)
  53.   ;; generalize to other compilers
  54.   ;; DEFAULT is the Common Lisp compiler
  55.   (compiler            #'compile-file :type function)
  56.   ;; generalize to other loaders
  57.   (loader              #'load         :type function)
  58.   (suffixes            *suffixes*     :type list)
  59.   #+:LCL4.0
  60.   (source-file         nil)
  61.   (documentation       nil             :type (or NULL string))
  62.   )
  63.  
  64. (defun print-system (system stream level)
  65.   (declare (ignore level))
  66.   (format stream "#<System ~A>" (system-name system)))
  67.  
  68. (defstruct (module (:print-function print-module))
  69.   (name "")
  70.   (load-before-compile nil)
  71.   (compile-only nil)
  72.   (load-after nil)
  73.   (recompile-on nil)
  74.   (pathname nil)
  75.   (dtm 0)
  76.   (package nil)
  77.   (in-process nil)
  78.   (being-loaded nil)            ; to avoid recursion in loading
  79.   (loaded nil)
  80.   (type )
  81.   (source-path)                ; cache module-source-file
  82.   (binary-path)                ; cache module-binary-file
  83.   ;; generalize to other compilers
  84.   (compiler nil :type (or NULL function))
  85.   ;; DEFAULT is the Common Lisp compiler
  86.   ;; generalize to other loaders
  87.   (loader  nil :type (or NULL function))
  88.   (suffixes nil :type list)
  89.   )
  90.  
  91. (defmacro domodules ((module system &key recursive-p) &rest body)
  92.   (let ((s (gentemp)))
  93.     `(let* ((,s ,system))
  94.       (dolist (system-name ,(if recursive-p
  95.                 `(system-needed-systems* ,s)
  96.                   `(list ,s)))
  97.     (let ((system (find-system system-name)))
  98.       (dolist (module-name (system-module-list system))
  99.         (let ((,module (module-source-file (find-module module-name system)
  100.                            system)))
  101.           . ,body)))))))      
  102.  
  103. (defmacro with-package ((module system) &rest body)
  104.   `(let ((p (or (module-package ,module) (system-default-package ,system))))
  105.     (if p
  106.     (let ((*package* (if (typep p 'PACKAGE)
  107.                  p
  108.                (or (find-package p)
  109.                    (error "Unknown package ~S" p)))))
  110.       .,body)
  111.       (progn .,body))))
  112.  
  113. (proclaim '(inline module-load-only))
  114. (defun module-load-only (module)
  115.   (member (module-type module) '(:LISP-SOURCE :LISP-BINARY)))
  116.  
  117. (proclaim '(inline module-not-to-be-loaded))
  118. (defun module-not-to-be-loaded (module)
  119.   (declare (type module module))
  120.   (or (module-compile-only module)
  121.       (member (module-type module)
  122.           '(:LISP-EXAMPLE :TEXT))))
  123.  
  124. (proclaim '(inline module-not-to-be-compiled))
  125. (defun module-not-to-be-compiled (module)
  126.   (declare (type module module))
  127.   (member (module-type module)
  128.       '(:LISP-BINARY :LISP-SOURCE :LISP-EXAMPLE :TEXT)))
  129.  
  130. (defun print-module (module stream level)
  131.   (declare (ignore level))
  132.   (format stream "#<Module ~A>" (module-name module)))
  133.  
  134. (defvar *all-systems* nil)
  135. (defvar *loaded-systems* nil)
  136.  
  137. (defmacro undefsystem (system-name)
  138.   (if (symbolp system-name)
  139.       `(let ((system (find-system ',system-name nil)))
  140.     (if system
  141.         (setq *all-systems* (remove system *all-systems* :key #'cdr))
  142.       (warn "System ~S was not defined." ',system-name)))
  143.     (error "Argument should be a symbol, not ~S." system-name))
  144.   )
  145.  
  146. (defvar *relative-binary-namestring* "")
  147.  
  148. (defun canonical-pathname (key arg &aux (sep #+:CCL #\: #-:CCL #\/))
  149.   ;; If the pathname is a string, this will be the source directory.
  150.   ;; The binary directory will default relative to it, appending the string
  151.   ;; *relative-binary-namestring*
  152.   (flet ((wrng-args ()
  153.        (error "Pathname should be a string or a dotted pair of strings, not~% ~S ~S .."
  154.           key arg)))
  155.     (flet ((append-seperator? (s)
  156.          (let ((ln (length s)))
  157.            (if (zerop ln)
  158.            (string sep)
  159.          (if (let ((end (elt s (1- ln))))
  160.                        (or (char= end sep)
  161.                            #+MCL (char= end #\;)
  162.                            ))
  163.              s
  164.            (concatenate 'string s (string sep)))))))
  165.       (flet ((pre-process-pathname (s)
  166.            (let* ((s (expand-file-name s))
  167.               (ln (length s)))
  168.          (if (zerop ln)
  169.              (wrng-args)
  170.            (append-seperator?
  171.             (concatenate 'string
  172.                  (append-seperator? s)
  173.                  *relative-binary-namestring*))))))
  174.     (flet ((expand&append-sep (s)
  175.          (append-seperator? (expand-file-name s))))
  176.       (or (typecase arg
  177.         (STRING (cons (expand&append-sep arg) (pre-process-pathname arg)))
  178.         (CONS (if (and (stringp (car arg))
  179.                    (stringp (cdr arg)))
  180.               (cons (expand&append-sep (car arg))
  181.                 (expand&append-sep (cdr arg)))))
  182.         (PATHNAME arg)
  183.         (T nil))
  184.           (wrng-args)))))))
  185.  
  186. (defun pre-process-options (whole-key-value-list modules-p &aux all-keys)
  187.   (flet ((canonical-modules (ms)
  188.        (let ((cms (if (or (stringp ms)
  189.                   (and (consp ms)
  190.                    (symbolp (car ms))
  191.                    (or (eq T (cadr ms))
  192.                        (every #'(lambda (m) (stringp m))
  193.                           (cdr ms)))))
  194.               (list ms)
  195.             (if (consp ms)
  196.                 ms
  197.               (error "Wrong syntax for Module ~S" ms)))))
  198.          (do ((cmtl cms (cdr cmtl))) ((null cmtl))
  199.            (when (member (car cmtl) (cdr cmtl) :test #'equal)
  200.          (error "Multiply mentioned module ~S in ~S."
  201.             (car cmtl) (cdr whole-key-value-list))))
  202.          cms))
  203.      
  204.      (av (key val keylist)        ; add a value
  205.        (let ((v (if (consp val) val (list val))))
  206.          (do ((tl keylist (cddr tl)))
  207.          ((null tl) (cons key (cons v keylist)))
  208.            (when (eq (car tl) key)
  209.          (let* ((tl1 (cdr tl))
  210.             (v1 (if (consp (car tl1)) (car tl1) (list (car tl1)))))
  211.            (setf (cadr tl) (remove-duplicates (append v v1)
  212.                               :from-end t
  213.                               :test #'equal))
  214.            (return keylist))))))
  215.  
  216.      (canonical-systems (arg)
  217.        (if (listp arg) arg (list arg)))
  218.      (wrng-arg (key arg)
  219.        (error "The system option ~S (expecting a symbol or function) was given: ~S instead"
  220.           key arg)))
  221.     
  222.     (labels ((pre-process-tail (key-value-list)
  223.            (when key-value-list
  224.          (let ((key (car (the cons key-value-list))))
  225.            (if (keywordp key)
  226.                (if (consp (cdr (the cons key-value-list)))
  227.                (let ((arg (cadr (the cons key-value-list)))
  228.                  (Rargs (cddr key-value-list)))
  229.                  (if (member key all-keys)
  230.                  (error "Multiple use of keyword ~S ~S ..." key arg)
  231.                    (push key all-keys))
  232.                  (case key
  233.                    ((:default-pathname :pathname)
  234.                 (list* key
  235.                        (canonical-pathname key arg)
  236.                        (pre-process-tail Rargs)))
  237.                    ((:load-before-compile :needed-systems)
  238.                 (list* key
  239.                        (if modules-p
  240.                        (canonical-modules arg)
  241.                      (canonical-systems arg))
  242.                        (pre-process-tail Rargs)))
  243.                    ((:recompile-on :load-after)
  244.                 (list* key
  245.                        (canonical-modules arg)
  246.                        (pre-process-tail Rargs)))
  247.                    ((:package :default-package)
  248.                 (list* key
  249.                        (string arg)
  250.                        (pre-process-tail Rargs)))
  251.                    ((:compiler :loader)
  252.                 (list* key
  253.                        (typecase arg
  254.                      (SYMBOL arg)
  255.                      (CONS (case (car (the cons arg))
  256.                          ((FUNCTION QUOTE) (eval arg))
  257.                          (T (wrng-arg key arg))))
  258.                      (T (wrng-arg key arg)))
  259.                        (pre-process-tail Rargs)))
  260.                    (:suffixes
  261.                 (list* key
  262.                        (if (consp arg)
  263.                        arg
  264.                      (cons arg arg))
  265.                        (pre-process-tail Rargs)))
  266.                    (t (list* key
  267.                      (cadr key-value-list)
  268.                      (pre-process-tail Rargs)))))
  269.              (error "Odd length option list ~S." key-value-list))
  270.              (error
  271.               "Keyword expected in module-description ~S instead of ~S."
  272.               (cdr whole-key-value-list) key))))))
  273.       (when modules-p
  274.     (let ((p1 (position ':load-always whole-key-value-list)))
  275.       (when p1
  276.         (let* ((p1-tail (nthcdr (1+ p1) whole-key-value-list))
  277.            (arg (canonical-modules (car p1-tail))))
  278.           (setf whole-key-value-list
  279.             (av ':load-before-compile
  280.             arg
  281.             (av ':load-after
  282.                 arg
  283.                 (nconc (subseq whole-key-value-list 0 p1)
  284.                    (cdr p1-tail)))))))))
  285.       (pre-process-tail whole-key-value-list))))
  286.  
  287.  
  288. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  289. ;;                                  defsystem
  290. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  291.  
  292. (defmacro defsystem (system-name options &body modules)
  293.   (check-type system-name symbol)
  294.   (check-type options list)
  295.   `(let* ((system-construct (append '(:name ,system-name)
  296.                     ',(pre-process-options options nil)))
  297.       mod-list
  298.       (system (apply #'make-system system-construct))
  299.       (loader (system-loader system))
  300.       (compiler (system-compiler system))
  301.       (suffixes (system-suffixes system))
  302.       (system-mods (system-modules system)))
  303.     (dolist (module ',modules)
  304.       (let* ((mod-construct
  305.           (if (consp module)
  306.           (cons ':name module)
  307.         (if (stringp module)
  308.             (list ':name module)
  309.           (error "Expecting a module description instead of: ~S."
  310.              module))))
  311.          (module-structure
  312.           (apply #'make-module
  313.              (pre-process-options mod-construct t)))
  314.          (module-name (module-name module-structure)))
  315.     (if (member module-name mod-list :test #'equal)
  316.         (error "Module ~S multiply defined." module-name)
  317.       (push module-name mod-list))
  318.     (unless (module-loader module-structure)
  319.       (setf (module-loader module-structure)
  320.         (if (and (module-type module-structure)
  321.              (member (module-type module-structure)
  322.                  '(:LISP :LISP-EXAMPLE)))
  323.             #'load
  324.             loader)))
  325.     (unless (module-type module-structure)
  326.       (setf (module-type module-structure) ':LISP))
  327.     (unless (module-compiler module-structure)
  328.       (setf (module-compiler module-structure) compiler))
  329.     (unless (module-suffixes module-structure)
  330.       (setf (module-suffixes module-structure) suffixes))
  331.     (setf (gethash (module-name module-structure) system-mods)
  332.           module-structure) ) )
  333.     (setf (system-module-list system) (nreverse mod-list))
  334.     #+LCL4.0
  335.     (when (boundp '*load-pathname*)
  336.       (setf (system-source-file system) (namestring *load-pathname*)))
  337.     (redefine-system ',system-name system)      
  338.     ',system-name
  339.     )
  340.   )
  341.  
  342. (defun redefine-system (system-name system)
  343.   (let ((system-entry (assoc system-name *all-systems*)))
  344.     (if system-entry
  345.     (let* ((old-system (cdr system-entry))
  346.            (old-modules (system-modules old-system))
  347.            (loaded t))
  348.       ;; find out whether the old system was loaded
  349.       (dolist (module-name (system-module-list system))
  350.         (let ((md (gethash module-name old-modules)))
  351.           (if (and md (module-loaded md))
  352.         (let ((new-module (find-module module-name system)))
  353.           (if (and (subsetp (module-load-before-compile new-module)
  354.                     (module-load-before-compile md)
  355.                     :test #'equal)
  356.                (subsetp (module-load-after new-module)
  357.                     (module-load-after md)
  358.                     :test #'equal)
  359.                (subsetp (module-recompile-on new-module)
  360.                     (module-recompile-on md)
  361.                     :test #'equal))
  362.               (setf (module-loaded new-module) t
  363.                 (module-dtm new-module) (module-dtm md))
  364.             (setf loaded nil)))
  365.         (setf loaded nil))))
  366.       (unless loaded
  367.         (setf *loaded-systems* (delete system-name *loaded-systems*)))
  368.       (setf (cdr system-entry) system))  
  369.       (push (cons system-name system) *all-systems*))))
  370.  
  371. ;----------------------------------------------------------------------------;
  372. ; load-system
  373. ;------------
  374. ; Exported function to load a system
  375. (defun load-system (system-name &key reload (include-components T) preview
  376.                 (if-source-newer :load-source)
  377.                 (level 0)
  378.                 (memo-tag (list nil));; a unique id of this call
  379.                 &aux *load-verbose*)
  380.   (declare (special *load-verbose*
  381.             include-components if-source-newer level memo-tag))
  382.   (flet ((load-modules (modules system)
  383.        (dolist (module modules)
  384.          (let ((a-module (find-module module system)))
  385.            ;; If already loaded then only reload if needed
  386.            (unless (module-not-to-be-loaded a-module)
  387.          (load-if-needed a-module system reload preview))))))
  388.     (let* ((*load-if-source-newer* if-source-newer)
  389.        (system-entry (assoc system-name *all-systems*))
  390.        (system (if system-entry
  391.                (cdr system-entry)
  392.              (load-system-definition system-name))))
  393.       ;; if we have already loaded this system with the same memo-tag skip rest
  394.       (when (eq (system-memo system) memo-tag)
  395.     (return-from load-system (values)))
  396.       (unless preview
  397.     (format T "~%~%;;; ~V@TLoading system ~S" level system-name))
  398.       ;; Load subsystems
  399.       (load-needed-systems system reload preview)
  400.       ;; if there is a :default-load-module then load only it
  401.       (let ((lmod (system-default-load-module system)))
  402.     (when lmod            ; NIL means: don't load any module
  403.       (load-modules
  404.        (if (consp lmod)
  405.            lmod
  406.          (if (eq lmod T)        ; T   means: load ALL modules
  407.          (system-module-list system)
  408.            (list lmod)))
  409.        system)))
  410.       (unless preview
  411.     (format T "~%;;; ~V@TDone loading system ~S~%" level system-name)
  412.     (pushnew system-name *loaded-systems*)
  413.     (setf (system-needs-update system) nil))
  414.       (setf (system-memo system) memo-tag)
  415.       (values))))
  416.  
  417. (defun load-needed-systems (system reload preview)
  418.   (declare (special include-components if-source-newer level memo-tag))
  419.   (dolist (subsystem-name (system-needed-systems system))
  420.       (let ((subsystem (find-system subsystem-name nil)))
  421.     (unless subsystem
  422.       (setq subsystem (load-system-definition subsystem-name :errorp t)))
  423.     (when (and include-components
  424.            (or reload
  425.                (multiple-value-bind (loaded? needs-reload?)
  426.                (SYSTEM-LOADED-P subsystem-name)
  427.              (or (not loaded?)
  428.                  needs-reload?))))
  429.       (load-system subsystem-name
  430.                :reload reload
  431.                :include-components include-components
  432.                :preview preview
  433.                :if-source-newer if-source-newer
  434.                :level (+ level 2)
  435.                :memo-tag memo-tag))))
  436.   )
  437.  
  438. ;----------------------------------------------------------------------------;
  439. ; load-if-needed
  440. ;---------------
  441. ; load the module of the system, possibly again, possibly just previewing
  442. ; returns no value
  443.  
  444. (defun load-if-needed (module system &optional reload preview)
  445.   (flet ((do-load (path)
  446.        ;; never force to reload any :load-after module
  447.        (let ((load-after (module-load-after module))
  448.          (needed-systems+ (system-needed-systems*-aux system)))
  449.          (dolist (m load-after)
  450.            (if (stringp m)
  451.            (multiple-value-bind (mod system)
  452.                (find-module-among-systems m needed-systems+)
  453.              (load-if-needed mod system nil preview))
  454.          (load-from-system m nil preview t))))
  455.        (if preview
  456.            (format T "~%;;; Need to load: ~S" path)
  457.          (let ((loader (module-loader module)))
  458.            (unless (or (functionp loader)
  459.                (and (symbolp loader) (fboundp loader)))
  460.          (error "Load function ~S (of ~S) is not a defined function."
  461.             loader system))
  462.            (format T "~%;;; Loading file ~S" path)
  463.            (prog1 (with-package (module system)
  464.             (funcall loader path))
  465.          (setf (module-loaded module) T
  466.                (module-dtm module) (file-write-date path)))))))
  467.     (let ((path (get-pathname module system)) R)
  468.       (if (null path)
  469.       (module-not-found module system)
  470.     (when (and (not (module-being-loaded module))
  471.            (or reload
  472.                (not (module-loaded module))
  473.                (module-needs-reload-p* module system)))
  474.       (unwind-protect (setf (module-being-loaded module) t
  475.                 R (do-load path))                
  476.         (setf (module-being-loaded module) nil))))
  477.       R)))
  478.  
  479. (defun load-from-system (module-ref reload preview &optional test-load?)
  480.   ;; MODULE-REF: (<SYSTEM> m1 m2 ...) || (<SYSTEM> t)
  481.   (if (consp module-ref)
  482.       (let ((modules (rest module-ref)))
  483.     (if (eq (car (the cons modules)) 'T)
  484.         (load-system (car (the cons module-ref))
  485.              :reload reload :preview preview)
  486.       (let ((sys (find-system! (car (the cons module-ref)))))
  487.         ;; (load-needed-systems sys reload preview)
  488.         (dolist (module-name modules)
  489.           (let ((module (find-module module-name sys)))
  490.         (when (not (and test-load?
  491.                 (member (module-type module)
  492.                     '(:LISP-EXAMPLE :TEXT))))
  493.           (load-if-needed module sys reload preview))))
  494.         )))
  495.     (error "~S is not a module description" module-ref)))
  496.     
  497.     
  498. ;----------------------------------------------------------------------------;
  499. ; compile-system
  500. ;---------------
  501. ; Exported function to compile a system
  502. ; will try to locate the definition first
  503.  
  504. (defun compile-system (system-name &rest keyword-pairs
  505.                    &key reload recompile
  506.                    (include-components T) preview
  507.                    (memo-tag (list nil)) ;; a unique id of this call
  508.                    &allow-other-keys
  509.                    &aux system compiled-modules *load-verbose*
  510.                    (level 0))
  511.   (declare (special system compiled-modules *load-verbose* level)
  512.        (type symbol system-name))
  513.   (check-type system-name symbol)       
  514.   (let ((system-entry (assoc system-name *all-systems*)))
  515.     ;; try to find and load the system definition
  516.     (setq system (if system-entry
  517.              (cdr system-entry)
  518.            (load-system-definition system-name :errorp t)))
  519.     ;; if we have already compiled this system with the same memo-tag skip rest
  520.     (when (eq (system-memo system) memo-tag)
  521.       (return-from compile-system (values)))
  522.     ;; Recompile included systems
  523.     (dolist (subsystem-name (system-needed-systems system))
  524.       (let ((subsystem (find-system! subsystem-name)))
  525.     (when include-components
  526.       (unless (eq (system-memo subsystem) memo-tag)
  527.         (unless preview (format T "~%;;; Compiling System ~S" subsystem-name))
  528.         (compile-system subsystem-name
  529.                 :reload reload :recompile recompile
  530.                 :include-components include-components
  531.                 :preview preview :memo-tag memo-tag)))))
  532.     ;; Compile modules:
  533.     ;; compiled-modules = list of module-names that needed to be compiled
  534.     (dolist (module (system-module-list system))
  535.       (unless (module-not-to-be-compiled (find-module module system))
  536.     (multiple-value-bind (d c)
  537.         (apply #'compile-if-needed
  538.            module
  539.            (if compiled-modules
  540.                nil        ; we have already done the dependencies
  541.              #'(lambda ()    ; Load Compile subsystem dependencies
  542.              (dolist (subsystem-name (system-load-before-compile system))
  543.                (let ((subsystem (find-system! subsystem-name)))
  544.                  (when (or reload
  545.                        (not (member subsystem-name *loaded-systems*))
  546.                        (system-needs-update subsystem))
  547.                    (load-system subsystem-name
  548.                         :reload reload
  549.                         :include-components t ; always load needed systems
  550.                         :preview preview))))))
  551.            keyword-pairs)
  552.       (declare (ignore d))
  553.       (when c (push module compiled-modules)))))
  554.     (setf (system-memo system) memo-tag)
  555.     (if compiled-modules
  556.     (if preview
  557.         (format t "~%;;; In System ~S, need to compile:~%;;; ~{~A ~}"
  558.             system-name (nreverse compiled-modules))
  559.       (format t "~%;;; Compiled System ~S" system-name))
  560.       (format t "~%;;; System ~S needs no compilation." system-name))
  561.     (values)))
  562.  
  563. ;----------------------------------------------------------------------------;
  564. ; compile-if-needed
  565. ;------------------
  566. ; return 2 values
  567. ;   (1) the date/time of the latest compilation
  568. ;   (2) whether or not the module was actually compiled
  569.  
  570. (defun compile-if-needed (module-name
  571.               ;; before really compiling possibly do this
  572.               prep-thunk
  573.               &rest keyword-pairs
  574.               &key reload recompile preview 
  575.                    needed    ; if the user wants do it!
  576.               &allow-other-keys
  577.               &aux bpath sdtm bdtm (ddtm 0))
  578.   (declare (special system compiled-modules))
  579.   (macrolet ((module-set (MS-desc system)
  580.            ;; MS-desc: (<SYSTEM> m1 m2 ...) || (<SYSTEM> t)
  581.            `(let ((ms (cdr (the cons ,MS-desc))))
  582.          (if (eq (car (the cons ms)) 'T)
  583.              (system-module-list ,system)
  584.            ms))))
  585.     (flet ((load-dependees (modules systems)
  586.          (dolist (name modules)
  587.            (if (stringp name)
  588.            (multiple-value-bind (m s)
  589.                (find-module-among-systems name systems)
  590.              (load-if-needed m s reload preview))
  591.          (load-from-system name reload preview t)))))
  592.       (let* ((module  (find-module module-name system))
  593.          (spath (let ((p (module-source-file module system)))
  594.               (or p (error "Can't find the source file for ~S.~%" module-name)))))
  595.     (remf keyword-pairs ':needed)    ; just for call from compile-module
  596.     ;; Do our dependents unless this module is being processed
  597.     (unless (or (module-in-process module) (null (module-recompile-on module)))
  598.       (unwind-protect
  599.            ;; We don't want to recurse infinitely if one module has
  600.            ;; a reciprocal compile relation with another so we set the
  601.            ;; in-process flag to cause this to bottom out.  The
  602.            ;; unwind-protect makes sure it's cleaned up on error cases.
  603.            (let ((needed-systems* (system-needed-systems*-aux system)))
  604.          (setf (module-in-process module) T)
  605.          (dolist (mod (module-recompile-on module))
  606.            (if (stringp mod)
  607.                (multiple-value-bind (m system)
  608.                (find-module-among-systems mod needed-systems*)
  609.              (declare (special system))
  610.              (if (member mod compiled-modules :test #'equal)
  611.                  (setq ddtm (max (file-write-date
  612.                           (module-binary-file m system))
  613.                          ddtm))
  614.                (multiple-value-bind (date compiled?)
  615.                    (apply #'compile-if-needed
  616.                       mod
  617.                       prep-thunk
  618.                       :allow-other-keys t
  619.                       keyword-pairs)
  620.                  (setq ddtm (max date ddtm))
  621.                  (if compiled? (setq prep-thunk nil)))))
  622.              (let ((system (find-system (car mod))))
  623.                (declare (special system))
  624.                (dolist (module-name (module-set mod system))
  625.              (unless (module-not-to-be-compiled
  626.                   (find-module module-name system)) 
  627.                (multiple-value-bind (date compiled?)
  628.                    (apply #'compile-if-needed
  629.                       module-name
  630.                       prep-thunk
  631.                       :allow-other-keys t
  632.                       keyword-pairs)
  633.                  (setq ddtm (max date ddtm))
  634.                  (if compiled? (setq prep-thunk nil)))))))))
  635.         (setf (module-in-process module) nil)))
  636.     ;; compile the module if its binary is older than its source or dependee
  637.     (setq bpath (module-binary-file module system)
  638.           sdtm (file-write-date spath)
  639.           bdtm (if (probe-file bpath) (file-write-date bpath) 0))
  640.     (if (and (or needed (< bdtm sdtm) (< bdtm ddtm)
  641.              (and recompile (not (member module-name compiled-modules))))
  642.          (not (module-in-process module)))
  643.         ;; Recompiling.. load necessary files
  644.         (let ((needed-systems* nil)
  645.           (recompile-on (module-recompile-on module))
  646.           (load-before-compile (module-load-before-compile module)))
  647.           ;; Now, do the postponed load of the subsystems
  648.           (when prep-thunk (funcall prep-thunk))
  649.           (when (or recompile-on load-before-compile)
  650.         (setq needed-systems* (system-needed-systems*-aux system)))
  651.           (load-dependees recompile-on needed-systems*)
  652.           (load-dependees load-before-compile needed-systems*)
  653.           (let ((universal-time (get-universal-time)))
  654.         (unless preview
  655.           (format T "~%;;; Compiling Module ~S (of ~S) to ~S"
  656.               (module-name module) (system-name system) (namestring bpath))
  657.           (let ((compiler (module-compiler module)))
  658.             (unless (or (functionp compiler) (and (symbolp compiler) (fboundp compiler)))
  659.               (error "Compile function ~S (of ~S) is not a defined function."
  660.                  compiler system))
  661.               (let (compiled?)
  662.             (unwind-protect
  663.                  (setq compiled?
  664.                    (with-package (module system)
  665.                      (apply compiler spath
  666.                         :output-file bpath
  667.                         :allow-other-keys t
  668.                         keyword-pairs)))
  669.               ;; if an error occurs during compilation remove the partially written
  670.               ;; file, that some compiler may leave around
  671.               (when (and (not compiled?) (probe-file bpath))
  672.                 (delete-file bpath)))))
  673.           (terpri))
  674.         (setf (system-needs-update system) T)
  675.         ;; recompiling produces a new file so it is up to date
  676.         ;; until the point of START of compilation
  677.         (values universal-time t)))
  678.       ;; Not recompiling or in process..
  679.       (values (max bdtm sdtm) nil))))))
  680.  
  681. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  682. ;;                                  Pathnames
  683. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  684.  
  685. (proclaim '(inline path-source-path path-bin-path))
  686. (defun path-source-path (mpath)
  687.   (if (consp mpath) (car (the cons mpath)) mpath))
  688.  
  689. (defun path-bin-path (mpath)
  690.   (if (consp mpath) (cdr (the cons mpath)) mpath))
  691.  
  692. ;; return nil if file is not found
  693. ;; otherwise return the pathname of the newer file, unless
  694. ;; *LOAD-IF-SOURCE-NEWER* is :LOAD-BINARY it will the binary instead
  695.  
  696. (defun get-pathname (module system)
  697.   (let* ((module-name (make-pathname :name (module-name module)))
  698.      (mpath (or (module-pathname module)
  699.             (setf (module-pathname module)
  700.               (system-default-pathname system))))
  701.      (spath (path-source-path mpath))
  702.      (bpath (path-bin-path mpath))
  703.      (suffixes (module-suffixes module))     
  704.      (sname (merge-pathnames (merge-pathnames module-name spath)
  705.                  (make-pathname :type (car suffixes))))
  706.      (bname (merge-pathnames (merge-pathnames module-name bpath)
  707.                  (make-pathname :type (cdr suffixes)))))
  708.     (if (probe-file sname)
  709.     (let ((sdtm (file-write-date sname)))
  710.       (if (probe-file bname)
  711.           (let ((bdtm (file-write-date bname)))
  712.         ;; Both exist take newer
  713.         (if (> sdtm bdtm)
  714.             (if (eq *LOAD-IF-SOURCE-NEWER* :LOAD-BINARY)
  715.             bname
  716.               sname)
  717.           bname))
  718.         sname))
  719.       (if (probe-file bname)
  720.       bname
  721.     nil))))
  722.  
  723. (defun module-source-file (module system)
  724.   (declare (type module module))
  725.   (or (module-source-path module)
  726.       (let* ((mpath (or (module-pathname module)
  727.             (setf (module-pathname module)
  728.                   (system-default-pathname system))))
  729.          (dir+name (merge-pathnames
  730.             (make-pathname :name (module-name module))
  731.             (path-source-path mpath)))
  732.          (source-path (merge-pathnames
  733.                dir+name
  734.                (make-pathname
  735.                 :type (car (module-suffixes module)))))
  736.          (probed-path (or (probe-file source-path)
  737.                   (probe-file dir+name)
  738.                   (return-from module-source-file nil))))
  739.     (setf (module-source-path module) probed-path))))
  740.  
  741. (defun module-binary-file (module system)
  742.   (declare (type module module))
  743.   ;; cache the value
  744.   (or (module-binary-path module)
  745.       (let ((mpath (or (module-pathname module)
  746.                (setf (module-pathname module)
  747.                  (system-default-pathname system)))))
  748.     (setf (module-binary-path module)
  749.           (merge-pathnames
  750.            (make-pathname :name (module-name module)
  751.                   :type (cdr (module-suffixes module)))
  752.            (path-bin-path mpath))))) )
  753. ;----------------------------------------------------------------------------;
  754. ; compile-module
  755. ;---------------
  756. ; Compile a module and any modules which this module depends on.
  757. ;  An attempt is made to find the system where this module was 
  758. ;  defined. By default needed modules which are loaded will 
  759. ;  not be reloaded.
  760.  
  761. (defun compile-module (module-name
  762.                &rest keyword-pairs
  763.                &key ((:system system-name)) reload preview
  764.                &allow-other-keys)
  765.   (let ((system (find-system-for-module module-name system-name))
  766.     compiled-modules)
  767.     (declare (special system compiled-modules))
  768.     (apply
  769.      #'compile-if-needed
  770.      module-name
  771.      #'(lambda ()
  772.      (dolist (subsystem-name (system-load-before-compile system))
  773.        (load-system subsystem-name
  774.             :reload reload
  775.             :include-components t ; always load needed systems
  776.             :preview preview)))
  777.      :needed t            ; recompile because the user wants it
  778.      keyword-pairs)
  779.     (values)    
  780.     ))
  781.  
  782. ;----------------------------------------------------------------------------;
  783. ; load-module
  784. ;------------
  785. ; load a module.  By default, the module will be reloaded.  The keyword argument 
  786. ; :reload may be used to avoid reload of the module and possibly all modules this 
  787. ; module depends on.  If the module description contains any :load-after
  788. ; modules, these will also be reloaded.
  789. (defun load-module (module-name
  790.             &key
  791.             ((:system system-name))
  792.             (if-source-newer :load-source)
  793.             (reload t) preview
  794.             &aux
  795.             (level 0)
  796.             (*load-if-source-newer* if-source-newer)
  797.             (system (find-system-for-module module-name system-name))
  798.             (module (find-module module-name system)))
  799.   (declare (special level))
  800.   (when (or reload (not (module-loaded module)))
  801.     (load-if-needed module
  802.             system
  803.             reload
  804.             preview
  805.             )))
  806.  
  807. (defun find-system-for-module (module-name system-name)
  808.   (cond ((null system-name)
  809.      ;; try to find one
  810.      (multiple-value-bind (module sys)
  811.          (find-module-among-systems
  812.           module-name (mapcar #'car *all-systems*))
  813.          (declare (ignore module))
  814.        sys))
  815.     ((symbolp system-name) (find-system! system-name))
  816.     (t (error "~S should be a symbol naming a defined system."
  817.           system-name))))
  818.  
  819. ;----------------------------------------------------------------------------;
  820. ; show-system
  821. ;------------
  822. ; The function {\tt show-system} produces a pretty output of the system
  823. ; description.
  824.  
  825. (defun show-system (system-name &optional (stream T))
  826.   (macrolet ((show (string val) `(when ,val (format stream ,string ,val))))
  827.     (let* (#+(and :LUCID (not :LCL4.0)) ( SYSTEM::*GC-SILENCE* T )
  828.            #+(and :LUCID :LCL4.0)       ( LCL:*GC-SILENCE* T )
  829.        #+Allegro ( EXCL::*GCPRINT* nil )
  830.        (system (find-system system-name))
  831.        (dashes "~%;;; ---------------------------------")
  832.        (system-path (system-default-pathname system))
  833.        *print-circle*)
  834.       (declare (type system system))
  835.       (format stream "~?~%;;; System: ~S is " dashes () system-name)
  836.       (multiple-value-bind (loaded? needs-reload?)
  837.       (SYSTEM-LOADED-P system-name)
  838.     (format stream "~:[not ~;~]loaded." loaded?)
  839.     (when loaded?
  840.       (format stream "~%;;; It ~:[does'nt need~;needs~] to be reloaded." needs-reload?))
  841.     (let ((lm (system-default-load-module system)))
  842.       (unless (eq lm 'T) (format T "~%;;; Default-load-module: ~S" lm)))
  843.     (show "~%;;; ~A" (system-documentation system))
  844.     (show "~%;;; Load-before-compile: ~{~S ~}" (system-load-before-compile system))
  845.     (show "~%;;; Needed Systems:      ~{~S ~}" (system-needed-systems system))
  846.     (show "~%;;; Default Package:     ~S" (system-default-package system))
  847.     (show "~%;;; Suffixes:            ~S" (system-suffixes system))
  848.     (unless (equal (pathname "") system-path)
  849.       (if (consp system-path)
  850.           (progn
  851.         (format stream "~%;;; Default Source Path:    ~S" (car system-path))
  852.         (format stream "~%;;; Default Binary Path:    ~S"
  853.             (cdr system-path)))
  854.         (format stream "~%;;; Default Path:    ~S" system-path)))
  855.  
  856.     #+:LCL4.0 (show "~%;;; Source file:     ~S" (system-source-file system))
  857.     (dolist (module-name (system-module-list system))
  858.       (show-module module-name :system system-name :verbose nil))
  859.     (system-circular-p system-name ':load-before-compile)
  860.     (system-circular-p system-name ':load-after)
  861.     (format stream dashes)
  862.     (values)))))
  863.  
  864. (defun show-module (module-name &key (system nil system-p) (verbose T) (stream T))
  865.   (macrolet ((show (string val) `(when ,val (format stream ,string ,val))))
  866.     (multiple-value-bind (module system)
  867.     (if system-p
  868.         (values (find-module module-name (find-system system))
  869.             (find-system system))
  870.       (find-module-among-systems
  871.        module-name (mapcar #'car *all-systems*)))
  872.       (let ((system-path (system-default-pathname system)))
  873.     (format stream "~%;;; Module: ~S~:[~; (of ~S)~]"
  874.         module-name verbose (system-name system))
  875.     (let ((type (module-type module)))
  876.       (unless (eq type :lisp) (format t " (type ~S)" (module-type module))))
  877.     (show " Package: ~S" (module-package module))
  878.     (format stream "~48,8T~:[Not ~;~]Loaded" (module-loaded module))
  879.     (let* ((spath  (module-source-file module system))
  880.            (bpath  (probe-file (module-binary-file module system)))
  881.            (sdtm   (and spath (file-write-date spath)))
  882.            (btm    (and bpath (file-write-date bpath)))
  883.            (mpath  (path-source-path (module-pathname module))))
  884.       (if spath
  885.           (progn
  886.         (if (null btm)
  887.             (unless (module-not-to-be-compiled module)
  888.               (format stream "  Needs Compilation"))
  889.           (when (> sdtm btm)
  890.               (format stream "  Needs Recompile")))
  891.         (when (and (module-loaded module)
  892.                (module-needs-reload-p module system))
  893.           (format stream "  Needs Reload")))
  894.         (format stream "~%;;;    Source not found in ~S"
  895.             mpath))
  896.       (show "~%;;;    Compile-only: ~S" (module-compile-only module))
  897.       (let* ((Load-before-compile (module-load-before-compile module))
  898.          (Load-after (module-load-after module))
  899.          (Load-always (intersection Load-before-compile Load-after :test #'equal)))
  900.         (show "~%;;;    Load-always: ~{~S ~}" Load-always)
  901.         (show "~%;;;    Load-before-compile: ~{~S ~}"
  902.           (set-difference Load-before-compile Load-always :test #'equal))
  903.         (show "~%;;;    Load-after: ~{~S ~}"
  904.           (set-difference Load-after Load-always :test #'equal)))
  905.       (show "~%;;;    Recompile-on: ~{~S ~}" (module-recompile-on module))
  906.       (unless (or (null mpath)
  907.               (equal mpath (path-source-path system-path)))
  908.         (format stream "~%;;;    Pathname: ~S" mpath))
  909.       (unless (equal (module-suffixes module) (system-suffixes system))
  910.         (format stream "~%;;;    Suffixes: ~S" (module-suffixes module))))
  911.     (values)))))
  912.  
  913. ;----------------------------------------------------------------------------;
  914. ; module-needs-reload-p
  915. ;----------------------
  916. ; return T if module is not loaded or it is loaded but either the binary or
  917. ; the source is younger than the loaded version
  918.  
  919. (defun module-needs-reload-p (module system)
  920.   (declare (type module module) (type system system))
  921.   (unless (module-not-to-be-loaded module)
  922.     (if (module-loaded module)
  923.     (let ((mdtm   (module-dtm module))
  924.           (spath  (module-source-file module system)))
  925.       #-:KCL (declare (fixnum mdtm) (pathname spath))
  926.       (when spath
  927.         (if (> (file-write-date spath) mdtm)
  928.         ;; the source is more recent ==> T
  929.         (return-from module-needs-reload-p
  930.           (setf (system-needs-update system) t))
  931.           ;; the source is older, how about the binary?
  932.           (let ((bpath (module-binary-file module system)))
  933.         (return-from module-needs-reload-p
  934.           (if (and (probe-file bpath)
  935.                (> (file-write-date bpath) mdtm))
  936.               ;; the binary is more recent ==> T
  937.               (setf (system-needs-update system) t)
  938.             nil)))))
  939.       ;; no source found
  940.       (let ((bpath (module-binary-file module system)))
  941.         (if (probe-file bpath)
  942.         (if (> (file-write-date bpath) mdtm)
  943.             (setf (system-needs-update system) t)
  944.           nil)
  945.           (error "Module not found ~S." (module-name module)))))
  946.       ;; module not loaded, so certainly it needs to be loaded
  947.       t)))
  948.  
  949. (defun module-needs-reload-p* (module system)
  950.   (or (module-needs-reload-p module system)
  951.       (some #'(lambda (pair)
  952.         (module-needs-reload-p (car pair) (cdr pair)))
  953.         (module-needed-modules*-aux module system))))
  954.  
  955. ;----------------------------------------------------------------------------;
  956. ; module-needs-recompile-p
  957. ;-------------------------
  958. ; return T if module its binary is older than its source
  959.  
  960.  
  961. (defun module-needs-recompile-p (module system)
  962.   (declare (type module module) (type system system))
  963.   (unless (module-not-to-be-compiled module)
  964.     (let ((bpath  (module-binary-file module system)))
  965.       (declare (pathname bpath))
  966.       (when (if (probe-file bpath)
  967.         (< (file-write-date bpath)
  968.            (file-write-date (module-source-file module system)))
  969.           t)
  970.     (setf (system-needs-update system) t)))))
  971.  
  972. (defun module-needs-recompile-p* (module system)
  973.   (or (module-needs-recompile-p module system)
  974.       (some #'(lambda (pair)
  975.         (module-needs-recompile-p (car pair) (cdr pair)))
  976.         (module-needed-modules*-aux module system))))
  977.  
  978. (defun system-needs-recompile-p (system)
  979.   (let (clean-systems)
  980.     (labels ((system-needs-recompile-p-aux (system)
  981.            (if (member system clean-systems)
  982.            nil
  983.          (or (system-needs-update system)
  984.              (some #'(lambda (module-name)
  985.                    (module-needs-recompile-p*
  986.                 (find-module module-name system) system))
  987.                (system-module-list system))
  988.              (some #'(lambda (system-name)
  989.                    (system-needs-recompile-p-aux (find-system system-name)))
  990.                (system-needed-systems system))
  991.              
  992.              (progn (push system clean-systems)
  993.                 ;;   (setf (system-needs-update system) nil)
  994.                 nil)
  995.  
  996.          ))))
  997.     (system-needs-recompile-p-aux system))))
  998.  
  999. (defun SYSTEM-COMPILED-P (system-name)
  1000.   (not (system-needs-recompile-p (find-system system-name))))
  1001.  
  1002. (defun MODULE-COMPILED-P (module-name 
  1003.               &key ((:system system-name) nil system-p))
  1004.   (declare (symbol system-name))
  1005.   (let (module system)
  1006.     (if system-p
  1007.     (setq system (find-system system-name)
  1008.           module (find-module module-name system))
  1009.       (multiple-value-setq (module system)
  1010.     (find-module-among-systems
  1011.      module-name
  1012.      (mapcar #'car *all-systems*)
  1013.      nil                ; no errors
  1014.      )))
  1015.     (not (module-needs-recompile-p* module system))))
  1016.  
  1017. ;----------------------------------------------------------------------------;
  1018. ; system-needed-systems*
  1019. ;-----------------------
  1020. ; given the name of a defined system, returns the
  1021. ; transitive closure of system-needed-systems
  1022.  
  1023. (defun system-needed-systems* (system-name &optional (recursive-p t))
  1024.   (let ((system (find-system system-name)))
  1025.     (if recursive-p
  1026.     (system-needed-systems*-aux system)
  1027.       (system-needed-systems system))))
  1028.  
  1029. (defun system-needed-systems*-aux (system)
  1030.   (labels ((system-needed-systems*-list (l)
  1031.          (if (null l)
  1032.          nil
  1033.            (union (system-needed-systems*-aux (find-system! (car l)))
  1034.               (system-needed-systems*-list (cdr l))))))
  1035.     (adjoin (system-name system)
  1036.         (system-needed-systems*-list (system-needed-systems system))))
  1037.   )
  1038.  
  1039. (defun module-needed-modules* (module-name system-name &optional (recursive-p t))
  1040.   (let* ((system (find-system system-name))
  1041.      (module (find-module module-name system))
  1042.      (needed-modules (module-load-after module)))
  1043.     (if recursive-p
  1044.     (mapcar #'(lambda (x) (module-name (car x)))
  1045.         (module-needed-modules*-aux module system))
  1046.       needed-modules)))
  1047.  
  1048. (defun module-needed-modules*-aux (module system &aux Acc)
  1049.   (macrolet ((module-set (MS-desc system)
  1050.            ;; MS-desc: (<SYSTEM> m1 m2 ...) || (<SYSTEM> t)
  1051.            `(let ((ms (cdr (the cons ,MS-desc))))
  1052.          (if (eq (car (the cons ms)) 'T)
  1053.              (system-module-list ,system)
  1054.            ms))))             
  1055.     (let ((ns (system-needed-systems*-aux system)))
  1056.       (labels ((module-needed-modules*-aux-0 (module-name All-ns)
  1057.          ;;(format t "~%-aux-0 ~S ~S ~%~S" module-name All-ns Acc)
  1058.          (unless (find-if
  1059.               #'(lambda (pair)
  1060.                   (string= (module-name (car pair)) module-name))
  1061.               Acc)
  1062.            (multiple-value-bind (mod system)
  1063.                (find-module-among-systems module-name All-ns t)
  1064.              ;; avoid recursion if modules need themselves
  1065.              (unless (assoc mod Acc)
  1066.                (push (cons mod system) Acc)
  1067.                (module-needed-modules*-aux-1 mod All-ns)))))
  1068.            (module-needed-modules*-aux-1 (module All-ns)
  1069.          ;;(format t "~%-aux-1 ~S ~S~%~S" module All-ns Acc)
  1070.          (dolist (module-descr (module-load-after module))
  1071.            (if (stringp module-descr)
  1072.                (module-needed-modules*-aux-0 module-descr All-ns)
  1073.              (let* ((system-name (car (the cons module-descr)))
  1074.                 (system (find-system system-name))
  1075.                 (new-All-ns (union (system-needed-systems system)
  1076.                            (adjoin system-name All-ns))))
  1077.                (dolist (module-name (module-set module-descr system))
  1078.              (unless (module-not-to-be-loaded
  1079.                   (find-module module-name system))
  1080.                (module-needed-modules*-aux-0
  1081.                 module-name new-All-ns))))))))
  1082.     (module-needed-modules*-aux-1 module ns)
  1083.     (nreverse Acc)))))
  1084.  
  1085. (defun find-module (m s &optional (errorp t))
  1086.   (declare (type system s))
  1087.   (setq m (string m))
  1088.   (let ((md (gethash m (system-modules s))))
  1089.     (if md
  1090.     md
  1091.       (when errorp (error "Module ~S not present in System ~S.~%"
  1092.               m s))
  1093.       )))
  1094.  
  1095. (defun find-module-among-systems (m systems &optional (errorp t))
  1096.   ;; systems : (list x:symbol)
  1097.   (dolist (system-name systems)
  1098.     (let ((system (find-system system-name errorp)))
  1099.       (when system
  1100.     (let ((module (find-module m system nil)))
  1101.       (when module
  1102.           (return-from find-module-among-systems
  1103.         (values module system)))))))
  1104.   (when errorp
  1105.     (error "Module ~S not present in Systems ~S.~%"
  1106.        m systems)))
  1107.  
  1108. ;----------------------------------------------------------------------------;
  1109. ; find-system
  1110. ;------------
  1111.  
  1112. (defun find-system (system-name &optional (errorp t))
  1113.   (let ((system-entry (assoc system-name *all-systems*)))
  1114.     (if system-entry
  1115.     (cdr system-entry)
  1116.       (when errorp
  1117.     (error "No ~S system description found!"
  1118.            system-name))
  1119.       )))
  1120.  
  1121. (defun find-system! (system-name)
  1122.   (or (find-system system-name nil)
  1123.       (load-system-definition system-name))
  1124.   )    
  1125.   
  1126. (defvar *system-directories* ())
  1127. (defun find-system-definition-file (system-name &optional (errorp t))
  1128.   (let ((filename (format nil "~A-sys" (string system-name))))
  1129.     (dolist (pathname (if (null *default-pathname-defaults*)
  1130.               *system-directories*
  1131.             (cons *default-pathname-defaults* *system-directories*)))
  1132.       (setq pathname (expand-file-name
  1133.               (typecase pathname
  1134.             (string pathname)
  1135.             (pathname (namestring pathname))
  1136.             (t (warn "~S is neither a string nor a pathname." pathname)
  1137.                (return)))))               
  1138.       (let ((binary-file (merge-pathnames
  1139.               (merge-pathnames filename
  1140.                        pathname)
  1141.               (make-pathname :type (cdr *suffixes*))))
  1142.         (source-file (merge-pathnames
  1143.               (merge-pathnames filename
  1144.                        pathname)
  1145.               (make-pathname :type (car *suffixes*)))))
  1146.     ;; (format t "~%~S~%~S" binary-file source-file)
  1147.     (cond ((and (probe-file binary-file)
  1148.             (probe-file source-file))
  1149.            (return-from find-system-definition-file
  1150.                 (if (> (file-write-date binary-file)
  1151.                    (file-write-date source-file))
  1152.                   binary-file
  1153.                   source-file)))
  1154.           ((probe-file binary-file)
  1155.            (return-from find-system-definition-file
  1156.                 binary-file))
  1157.           ((probe-file source-file)
  1158.            (return-from find-system-definition-file
  1159.                 source-file))
  1160.           ((probe-file (merge-pathnames filename pathname))
  1161.            (return-from find-system-definition-file
  1162.                 (merge-pathnames filename pathname))))))
  1163.     (when errorp
  1164.       (system-definition-not-found system-name))))
  1165.  
  1166. (defun load-system-definition (system-name &key (errorp t))
  1167.   ;; load the system-definition
  1168.   ;; return system-entry if successful
  1169.   ;; nil otherwise
  1170.   (let ((system-def (find-system-definition-file system-name errorp)))
  1171.     (if system-def
  1172.     (progn
  1173.       (format t "~%;;; Loading definition for system ~A from ~S"
  1174.           system-name system-def)
  1175.       (load system-def)
  1176.       (let ((system-entry (assoc system-name *all-systems*)))
  1177.         (if  system-entry
  1178.         (cdr system-entry)
  1179.           (when errorp
  1180.         (error "No ~S system definition loaded."
  1181.                system-name)))))
  1182.       (when errorp (system-definition-not-found system-name))))
  1183.   )
  1184. ;----------------------------------------------------------------------------;
  1185. ; system-loaded-p
  1186. ;----------------
  1187. ; returns two values: value1                          value2
  1188. ;                     T if  system is loaded          T if system is loaded
  1189. ;                                                       and needs reload
  1190. ;                     Nil   otherwise                 
  1191.  
  1192. (defun SYSTEM-LOADED-P (system-name)
  1193.   (declare (symbol system-name))
  1194.   (let ((loaded? (member system-name *loaded-systems*))
  1195.     (system (find-system system-name)))
  1196.     (if loaded?
  1197.     (dolist (ss (system-needed-systems*-aux system)
  1198.          (values t nil))
  1199.       (let ((subsystem (find-system ss)))
  1200.         (dolist (module (let ((lm (system-default-load-module subsystem)))
  1201.                   (if (eq lm 'T)
  1202.                   (system-module-list subsystem)
  1203.                 (if (consp lm)
  1204.                     lm
  1205.                   (list lm)))))
  1206.           (when (module-needs-reload-p*
  1207.              (find-module module subsystem) subsystem)
  1208.         (return-from SYSTEM-LOADED-P
  1209.           (values t (setf (system-needs-update system) t)))))))
  1210.       nil)))
  1211.     
  1212.  
  1213. ;----------------------------------------------------------------------------;
  1214. ; MODULE-LOADED-P
  1215. ;----------------
  1216. ; returns two values: value1                          value2
  1217. ;                     T if  module is loaded          T if module is loaded
  1218. ;                                                       and needs reload
  1219. ;                     Nil   otherwise                 
  1220.  
  1221. (defun MODULE-LOADED-P (module-name
  1222.             &key ((:system system-name) nil system-p))
  1223.   (declare (symbol system-name))
  1224.   (let (module system)
  1225.     (if system-p
  1226.     (setq system (find-system system-name)
  1227.           module (find-module module-name system))
  1228.       (multiple-value-setq (module system)
  1229.     (find-module-among-systems
  1230.      module-name
  1231.      (mapcar #'car *all-systems*)
  1232.      nil   ; no errors
  1233.      )))
  1234.     (if module
  1235.     (let ((loaded? (module-loaded module)))
  1236.       (values loaded?
  1237.           (and loaded?
  1238.                (module-needs-reload-p* module system))))
  1239.       (values nil nil))))
  1240.  
  1241. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1242. ;;                                   errors
  1243. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1244.  
  1245.  
  1246. (defun system-definition-not-found (system-name)
  1247.   (declare (symbol system-name))
  1248.   (error "A definition was not found for system ~A~%; looking for file ~A-sys in: ~{~S ~}."
  1249.      system-name (symbol-name system-name) *system-directories*))
  1250.  
  1251. (defun module-not-found (module system)
  1252.   (error "Can't find any file for module named ~S in system ~S."
  1253.      (module-name module) (system-name system))
  1254.   )
  1255.  
  1256. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1257. ;;                               cycle detection
  1258. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1259.  
  1260. (defun system-circular-p (system-name link)
  1261.   (let* ((system (find-system system-name))
  1262.      (context (cons system-name (system-needed-systems system)))
  1263.      (*print-circle* nil))
  1264.     (dolist (m (system-module-list system))
  1265.       (let ((cycle (detect-1-cycle
  1266.             (find-module m system)
  1267.             context
  1268.             nil
  1269.             (case link
  1270.               (:load-after #'module-load-after)
  1271.               (:load-before-compile #'module-load-before-compile)))))
  1272.     (when cycle
  1273.       (format t "~%;;; Warning: Circularity: ~S" cycle))))))
  1274.  
  1275. (defun detect-1-cycle (node context path get-children)
  1276.   ;; node:MODULE  path : ( STRING .. )
  1277.   ;; context : { SYSTEM | ( SYSTEM .. ) }
  1278.   (labels ((detect-1 (node context path)
  1279.          (let* ((mname (module-name node))
  1280.             (rpath (member mname path :test #'STRING=)))
  1281.            (if rpath
  1282.            (progn ;; (break)
  1283.               (setf (cdr rpath) nil)
  1284.               (return-from detect-1-cycle (cons mname path)))
  1285.          (let ((new-path (cons mname path)))
  1286.            (dolist (child (funcall get-children node))
  1287.              ;; child : { string | (<SYSTEM> string ..) | (<SYSTEM> t) }
  1288.              (if (consp child)
  1289.              (let ((system (find-system (car (the cons child)) nil)))
  1290.                (when system
  1291.                  (let ((context (list system)))
  1292.                    (dolist (gchild (if (eq (cadr child) 'T)
  1293.                            (system-module-list system)
  1294.                          (rest child)))
  1295.                  (let ((gchild-module (find-module gchild system)))
  1296.                    (when gchild-module
  1297.                      (detect-1 gchild-module
  1298.                            context
  1299.                            new-path)))))))
  1300.                (multiple-value-bind (child-module system)
  1301.                (find-module-among-systems child context nil)
  1302.              (when child-module
  1303.                (detect-1 child-module
  1304.                      (cons (system-name system)
  1305.                        (system-needed-systems system))
  1306.                      new-path))))))))))
  1307.     (detect-1 node context path)))
  1308.  
  1309. #||
  1310. (defsystem foo
  1311.     ()
  1312.   ("foo" :load-after "bar")
  1313.   ("bar" :load-after "baz")
  1314.   ("baz" :load-after "foo")
  1315.   )
  1316. (system-circular-p 'foo ':load-after) 
  1317. (system-circular-p 'foo ':load-always) 
  1318.  
  1319. (defsystem fie
  1320.     ()
  1321.   ("foo" :load-after "bar")
  1322.   ("bar" :load-after ((fum "baz")))
  1323.   )
  1324.  
  1325. (defsystem fum
  1326.     ()
  1327.   ("baz" :load-after ((fie t)))
  1328.   )
  1329.  
  1330. (show-system 'fie)
  1331. (show-system 'fum)
  1332. ||#
  1333.  
  1334. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1335. ;;                               end of defsys.l
  1336. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1337.